package com.example.service;

import com.alibaba.druid.support.json.JSONUtils;
import com.example.config.ElasticConfig;
import com.example.entity.ElastStudent;
import com.example.util.IdUtil;
import com.example.util.MyBeatUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.map.HashedMap;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class ElastServiceImpl implements  ElastService {

//    @Autowired
//    private ElasticConfig elasticConfig;
    @Autowired
    private  RestHighLevelClient restHighLevelClient;


    @Override
    public void addElastStudent(ElastStudent elastStudent) {
        /*
            插入可以通过entity-》string或者直接传map的方式
            如果用map方式，如果数据库字段和entity一样的话，有么有工具类将entity-》map
            BeanUtils.describe(entity);  apache的喔,妈的只能属性为string类型还有基本类型能转？？laji
            自己写个工具类吧，将entity转化成map，还可以使用驼峰(通过给属性名或者方法加注解，获取value),
         */
        //RestHighLevelClient client = elasticConfig.getHighLevelClient();//每次都要获取client，这个client应该是静态的吧
        Map<String,Object> map = new HashedMap();
        map= MyBeatUtil.entityToMap(elastStudent);
        //如果不支持插入date属性或者date属性特别，可以将date变成stringput进map，要format一下
        map.put("birthday",new  SimpleDateFormat("yyyy-MM-dd").format(elastStudent.getBirthday()));
        System.out.println(map.get("birthday"));
        IndexRequest indexRequest = new
                IndexRequest("student","doc", IdUtil.getRadomStr()).source(map);
        try {
            restHighLevelClient.index(indexRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void batchAddElastStudent(List<ElastStudent> studentList) {
        BulkRequest bulkRequest = new BulkRequest();
        for (ElastStudent student : studentList)
        {
            String source = JSONUtils.toJSONString(student);
            bulkRequest.add(new IndexRequest("student","doc").source(source, XContentType.JSON));
        }
        try {
            restHighLevelClient.bulk(bulkRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<ElastStudent> getTest(String name) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        searchSourceBuilder.from(0);
//        searchSourceBuilder.size(5);
        searchSourceBuilder.fetchSource(
                new String[]{"studentNo","name","male","age","birthday","address","classNo","isLeader"},null);
        searchSourceBuilder.sort("age", SortOrder.ASC);

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name",name);
        TermQueryBuilder queryBuilder = QueryBuilders.termQuery("male","男");
//        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("birthday");
//        rangeQueryBuilder.gte("1980-02-03");

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(matchQueryBuilder);
        boolQueryBuilder.must(queryBuilder);
        //boolQueryBuilder.must(rangeQueryBuilder);

        searchSourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest("student");
        //searchRequest.searchType("doc");
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(searchRequest);
            System.out.println(response);
            // /还有个header属性,headers 是一个可变参数，可以传入对应的 http 头信息
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<ElastStudent> elastStudentList= new ArrayList<>();
        if (response.getHits().getTotalHits()==0)
            return null;
        for (SearchHit searchHit :response.getHits()) {
            Map<String, Object> mymyp = searchHit.getSourceAsMap();
            //在这边去除date类型的string，在塞如date类型(一会看看能不能强转成date)
            String stringBir = (String) mymyp.get("birthday");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            try {
                Date date = sdf.parse(stringBir);
                mymyp.put("birthday",date);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            ElastStudent student = new ElastStudent();
            try {
                BeanUtils.populate(student, mymyp);//如果这边date类型为null，这个方法会报错，项目中还是自己set get吧
                //先把date设置成string类型吧，如果前台需要date类型，在添加一个dto好了
                //org.apache.commons.beanutils.ConversionException:
                // DateConverter does not support default TestString to 'Date' conversion.
                /*
                项目组的解决方式,我自己可以用simpledateformat来解决
                ZonedDateTime publishTime = ZonedDateTime.parse((CharSequence) sourceAsMap.get("publish_time"));
        resultEsDto.setPublishTime(Date.from(publishTime.toInstant()));
                 */
                elastStudentList.add(student);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return elastStudentList;
    }
}
